<template>
  <article class="page page-watermark-remove">
    <h4 class="text-center">图片去水印</h4>
    <form class="form">
      <div class="form-group">
        <fieldset>
          <legend>参数设置</legend>
          <div class="alert alert-info" role="alert">
            <div>注：从计算工作量的角度出发，本程序要求提供水印图片，且水印图片的尺寸&位置应与待处理图片保持一致。</div>
          </div>
          <div class="row">
            <div class="col col-6">
              <div class="row-flex" align="center">
                <div class="row-flex-prefix">水印图片</div>
                <div class="row-flex-main">
                    <input class="form-control" type="text" v-model.trim="watermarkPath" placeholder="请选择水印图片" />
                </div>
                <div class="row-flex-suffix"><x-button @click="setWatermarkPath">选择...</x-button></div>
              </div>
            </div>
            <div class="col col-6">
              <div class="row-flex" align="center">
                <div class="row-flex-prefix">下载位置</div>
                <div class="row-flex-main"><input class="form-control" type="text" v-model="toPath" /></div>
                <div class="row-flex-suffix"><x-button @click="setToPath">选择...</x-button></div>
              </div>
            </div>
          </div>
        </fieldset>
      </div>
      <div class="form-group form-group-main row">
        <div class="col col-6">
            <fieldset>
                <legend>图片列表</legend>
                <div class="fieldset-content">
                    <div class="pending-list" @drop.prevent="drop" @dragover.prevent >
                        <div class="pending-item" v-for="(v,i) in imagesList" :key="`pending_${i}`"
                          :class="{active: i === imageActiveIndex}"
                          @click.stop="clickImageItem(i)"
                        >
                            <div class="pending-item-text text-ellipsis" :title="v.path">{{v.name}}</div>
                            <div class="pending-item-status">{{imageStatusList[v.status]}}</div>
                            <div class="pending-item-btns">
                                <template v-if="v.status === 0">
                                    <button type="button" class="btn btn-link btn-sm" @click.stop="removeWatermarkItem(i)">去水印</button>
                                    <button type="button" class="btn btn-link btn-sm" @click.stop="imgItemDelete(i)">删除</button>
                                </template>
                                <template v-else-if="v.status === 1">
                                    <div class="pending-item-btn"><x-loading></x-loading></div>
                                </template>
                                <template v-else-if="v.status === 2">
                                    <button type="button" class="btn btn-link btn-sm" @click.stop="downloadSingleItem(i)">下载</button>
                                    <button type="button" class="btn btn-link btn-sm" @click.stop="imgItemDelete(i)">删除</button>
                                </template>
                            </div>
                        </div>
                        <div v-if="imagesList.length===0" class="nodata">将待处理的图片拖动到此处</div>
                    </div>
                </div>
            </fieldset>
        </div>
        <div class="col col-6">
            <fieldset>
                <legend>图片预览</legend>
                <div class="fieldset-content preview">
                    <img class="preview-img" :src="imagePreviewInfo.src1 || imagePreviewInfo.src" />
                    <div class="preview-name text-ellipsis">{{imagePreviewInfo.name}}</div>
                </div>
            </fieldset>
        </div>
      </div>
      <div class="form-group text-center">
        <x-button type="default" @click="clearImagesList">清空列表</x-button>
        <x-button type="primary" @click="removeWatermarkAll">去除水印</x-button>
        <x-button type="primary" @click="downloadAll">全部下载</x-button>
      </div>
    </form>
  </article>
</template>

<script>
const fs = global.require('fs')
const path = global.require('path')
const {remote} = global.require('electron')
const {dialog} = remote
const selfWindow= remote.getCurrentWindow()

export default {
  name: 'watermark-remove',
  data () {
    return {
        // 水印图片
        watermarkPath: '',
        watermarkInfo: {
            name: '水印图片', src: '', path: '', mimeType: '',
            imgObj: null, width: 0, height: 0, canvas: null, imgData: null
        },
        toPath: this.$sharedObject('desktopPath'),
        imagesList: [],
        imageActiveIndex: -1,
        imageStatusList: ['未处理', '正在处理', '已处理']
    }
  },
  computed: {
    imagePreviewInfo () {
        let imageActive = this.imagesList[this.imageActiveIndex]
        return imageActive || this.watermarkInfo
    }
  },
  methods: {
    // 设置水印图片位置
    setWatermarkPath () {
      let filePaths = dialog.showOpenDialogSync(selfWindow, {
        title: '选择文件',
        buttonLabel:'确定',
        defaultPath: this.$sharedObject('desktopPath'),
        properties: ['openFile'],
        filters: [ { name: '图片', extensions: ['png', 'jpg', 'jpeg', 'gif'] } ]
      })
      if (filePaths instanceof Array && filePaths.length > 0) {
        this.watermarkPath = filePaths[0]
        this.resetImagesList()
        this.getWatermarkInfo()
      }
    },
    // 设置下载位置
    setToPath () {
      let filePaths = dialog.showOpenDialogSync(selfWindow, {
        title: '选择目录',
        buttonLabel:'确定',
        defaultPath: this.$sharedObject('desktopPath'),
        properties: ['openDirectory']
      })
      if (filePaths instanceof Array && filePaths.length > 0) {
        this.toPath = filePaths[0]
      }
    },
    // 重置imagesList数据
    resetImagesList () {
      this.imagesList = this.imagesList.map(v => {
        return {...v, canvas: null, imgData: null, status: 0}
      })
    },
    // 拖拽添加文件
    drop (e) {
      const fileList = e.dataTransfer.files
      if (!fileList) return
      let taskList = []
      let indexList = []
      for (let i = 0; i < fileList.length; i++) {
        const file = fileList[i]
        if (!file.type || !/.(gif|jpg|jpeg|png)$/i.test(file.name)) {
          continue
        }
        taskList.push(this.$jstools.File2dataUrl(file))
        indexList.push(i)
      }
      Promise.all(taskList).then((urls) => {
        urls.forEach((v, i) => {
          let file = fileList[indexList[i]]
          this.imagesList.push({
            name: file.name, src: v, src1: '', path: file.path, ext: path.extname(file.path),
            mimeType: file.type, imgObj: null, width: 0, height: 0, canvas: null, imgData: null, status: 0
          })
        })
        this.loadImage()
      })
    },
    // 加载原始图片
    loadImage () {
      this.imagesList.forEach((v, i) => {
        if (v.imgObj) return
        this.$jstools.loadImage(v.src).then((imgObj) => {
            this.imagesList[i].imgObj = imgObj
            this.imagesList[i].width = imgObj.width
            this.imagesList[i].height = imgObj.height
        })
      })
    },
    // 获取水印图片信息
    getWatermarkInfo () {
        if (!this.watermarkPath || !fs.existsSync(this.watermarkPath)) {
            this.watermarkInfo = {
                name: '水印图片', src: '', path: this.watermarkPath, mimeType: '',
                imgObj: null, width: 0, height: 0, imgData: null, canvas: null
            }
            return
        }
        fs.readFile(this.watermarkPath, (err, data) => {
            if (err || !data) {
                this.$toast('获取水印图片信息发生错误')
                return
            }
            this.watermarkInfo.src = `data:image/png;base64,${data.toString('base64')}`
            this.$jstools.loadImage(this.watermarkInfo.src).then((imgObj) => {
                this.watermarkInfo.imgObj = imgObj
                this.watermarkInfo.width = imgObj.width
                this.watermarkInfo.height = imgObj.height
                this.watermarkInfo.imgData = this.getImgData(imgObj)
            })
        })
    },
    // 获取imgData
    getImgData (imgObj) {
        let canvasObj = document.createElement('canvas')
        canvasObj.width = imgObj.width
        canvasObj.height = imgObj.height
        let ctx = canvasObj.getContext('2d')
        ctx.drawImage(imgObj, 0, 0, canvasObj.width, canvasObj.height)
        let imgData = ctx.getImageData(0, 0, canvasObj.width, canvasObj.height)
        return imgData.data
    },
    // 点击图片
    clickImageItem (index) {
      if (this.imageActiveIndex === index) {
        this.imageActiveIndex = -1
      } else {
        this.imageActiveIndex = index
      }
    },
    // 删除图片
    imgItemDelete (index) {
      this.imagesList.splice(index, 1)
      if (this.imageActiveIndex === index) {
        this.imageActiveIndex = -1
      } else if (this.imageActiveIndex > index) {
        this.imageActiveIndex -= 1
      }
    },
    // 清空列表
    clearImagesList () {
      this.imagesList = []
      this.imageActiveIndex = -1
    },
    // 去除水印
    removeWatermarkAll () {
      if (this.imagesList.length <= 0) {
        this.$toast('未找到可处理的文件')
        return
      }
      let taskList = []
      this.imagesList.forEach((v, i) => {
        taskList.push(this.removeWatermarkItem(i))
      })
      Promise.all(taskList).finally(() => {
        this.$toast('图片处理完成')
      })
    },
    removeWatermarkItem (index) {
      return new Promise((resolve, reject) => {
        let item = this.imagesList[index]
        if (item.status !== 0) return reject('图片已处理或正在处理')
        item.status = 1
        this.$nextTick(() => {
          if (!item.imgData) {
              this.imagesList[index].imgData = this.getImgData(item.imgObj)
          }
          let imgData = this.imagesList[index].imgData
          let imgData_sy = this.watermarkInfo.imgData
          if (imgData.length !== imgData_sy.length) {
              this.$toast('待处理图片与水印图片大小不一致')
              return reject('待处理图片与水印图片大小不一致')
          }
          let bakColor = null
          for (let i = imgData.length - 4; i > -1; i -= 4) {
              if (!imgData_sy[i + 3]) {
                  bakColor = [imgData[i + 0], imgData[i + 1], imgData[i + 2], imgData[i + 3]]
                  continue
              } else if (imgData_sy[i + 3] === 255 && bakColor) {
                  imgData[i + 0] = bakColor[0]
                  imgData[i + 1] = bakColor[1]
                  imgData[i + 2] = bakColor[2]
                  imgData[i + 3] = bakColor[3]
                  continue
              }
              let opacity_sy = imgData_sy[i + 3] / 255
              let opacity_raw = (255 - imgData_sy[i + 3]) / 255
              imgData[i + 0] = (imgData[i + 0] - imgData_sy[i + 0] * opacity_sy) / opacity_raw
              imgData[i + 1] = (imgData[i + 1] - imgData_sy[i + 1] * opacity_sy) / opacity_raw
              imgData[i + 2] = (imgData[i + 2] - imgData_sy[i + 2] * opacity_sy) / opacity_raw
              if (imgData[i + 3] > 0 && imgData[i + 3] < 255) {
                imgData[i + 3] = (imgData[i + 3] - imgData_sy[i + 3]) / opacity_raw
              }
          }
          this.imagesList[index].imgData = imgData
          // imgData2dataUrl
          let canvasObj = document.createElement('canvas')
          canvasObj.width = item.imgObj.width
          canvasObj.height = item.imgObj.height
          let ctx = canvasObj.getContext('2d')
          let imageData = new ImageData(imgData, canvasObj.width, canvasObj.height)
          ctx.putImageData(imageData, 0, 0)
          this.imagesList[index].canvas = canvasObj
          this.imagesList[index].src1 = canvasObj.toDataURL('image/png')
          this.imagesList[index].status = 2
          resolve()
        })
      })
    },
    // 全部下载
    downloadAll () {
      if (!this.toPath) {
        this.$toast('请设置文件下载位置')
        return
      }
      if (this.imagesList.length <= 0) {
        this.$toast('未找到可下载的图片')
        return
      }
      let taskList = []
      this.imagesList.forEach((v, i) => {
        taskList.push(this.downloadItem(i))
      })
      Promise.all(taskList).finally(() => {
        this.$toast('下载完成')
      })
    },
    downloadSingleItem (index) {
      if (!this.toPath) {
        this.$toast('请设置文件下载位置')
        return
      }
      this.downloadItem(index).finally(() => {
        this.$toast('下载完成')
      })
    },
    downloadItem (index) {
      let item = this.imagesList[index] || {}
      let fileName = `qsy_${item.name}`
      let filePath = path.join(this.toPath, fileName)
      if (!item.canvas) return Promise.reject('无数据')
      return new Promise((resolve, reject) => {
        item.canvas.toBlob((blob) => {
          if (!blob) {return reject('无数据')}
          blob.arrayBuffer().then((res) => {
            this.$sharedObject('jstoolsNode').writeFile(filePath, Buffer.from(res))
            resolve()
          }).catch((err) => {
            reject('发生错误：' + err)
          })
        }, item.mimeType || 'image/png')
      })
    },
  }
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
.row-flex {
  & + .row-flex { margin-top: .5em; }
  .row-flex-prefix { width: 4.5em; text-align: left; }
}
.form {
  height: calc(100vh - 137px);
  display: flex;
  flex-direction: column;
  .form-group {
    fieldset {
        height: 100%;
        .fieldset-content {
            height: calc(100% - 2em);
            display: flex;
            flex-direction: column;
            .pending-list {
                height: 0;
                flex-grow: 1;
                padding: .5em;
                border-radius: .5em;
                background-color: #fff;
                box-shadow: 0 0 .5em @bgGrey;
                font-size: .9em;
                overflow: hidden auto;
                position: relative;
                .pending-item {
                    height: 2em;
                    padding-left: .5em;
                    padding-right: .5em;
                    display: flex;
                    align-items: center;
                    border-bottom: 1px dashed @borderGrey;
                    cursor: pointer;
                    &.active {
                      background-color: fade(@bgGrey, 50);
                    }
                    .pending-item-text { width: 0; flex-grow: 1; }
                    .pending-item-status { width: 8em; text-align: center; }
                    .pending-item-btns { width: 8em; text-align: center; }
                    .pending-item-btn { padding: 0 .5em; cursor: pointer; }
                }
            }
            .preview-img {
              display: block;
              max-width: 100%;
              max-height: 100%;
              object-fit: contain;
            }
            .preview-name {
              position: absolute;
              bottom: 0;
              left: 0;
              width: 100%;
              height: 2em;
              line-height: 2;
              color: #fff;
              text-align: center;
              background-color: rgba(0, 0, 0, .3);
            }
        }
        .preview {
          border-radius: .5em;
          background-color: @bgGrey;
          overflow: hidden;
          position: relative;
        }
    }
  }
  .form-group-main {
    height: 0;
    flex-grow: 1;
    & > .col {height: 100%;}
  }
  .alert-info { margin-bottom: 1em; }
}
</style>
